package com.glodon.paas.storage.ali;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import com.aliyun.common.auth.ServiceCredentials;
import com.aliyun.common.comm.DefaultServiceClient;
import com.aliyun.common.comm.ResponseMessage;
import com.aliyun.common.comm.ServiceClient;
import com.aliyun.common.utils.CodingUtils;
import com.aliyun.openservices.ClientConfiguration;
import com.aliyun.openservices.ClientException;
import com.aliyun.openservices.HttpMethod;
import com.aliyun.openservices.oss.OSSException;
import com.aliyun.openservices.oss.internal.OSSUtils;
import com.aliyun.openservices.oss.model.ObjectMetadata;
import com.glodon.paas.storage.Part;

/**
 * wrap operations relating with OSS Object Group, 
 * which are absent in the OSS SDK
 * 
 * @author guojf
 *
 */
public class OSSObjectGroupOperation extends OSSOperation {
	
	public static OSSObjectGroupOperation createInstance(String endpoint, String accessId, String accessKey) {
		CodingUtils.assertStringNotNullOrEmpty(endpoint, "endpoint");
		URI endpointUri = null;
		try {
			if (!endpoint.startsWith("http://")){
				throw new IllegalArgumentException("invalid endpoint protocal");
			}
			endpointUri = new URI(endpoint);
		} catch (URISyntaxException localURISyntaxException) {
			throw new IllegalArgumentException(localURISyntaxException);
		}
		ServiceCredentials credentials = new ServiceCredentials(accessId, accessKey);
		ServiceClient serviceClient = new DefaultServiceClient(new ClientConfiguration());
		return new OSSObjectGroupOperation(endpointUri, serviceClient, credentials);
	}
	
	protected OSSObjectGroupOperation(URI endpoint, ServiceClient client,
			ServiceCredentials credentials) {
		super(endpoint, client, credentials);
	}

	public CreateObjectGroupResult createObjectGroup(String bucket, String key,
			List<Part> parts, ObjectMetadata metadata) throws OSSException,
			ClientException {
		CodingUtils.assertParameterNotNull(bucket, "bucketName");
		CodingUtils.assertParameterNotNull(key, "key");
		OSSUtils.ensureBucketNameValid(bucket);
		OSSUtils.ensureObjectKeyValid(key);
		
		String requestXml = buildObjectGroupRequestXml(parts);
		byte[] requestBytes = null;
		try {
			requestBytes = requestXml.getBytes("utf-8");
		} catch (UnsupportedEncodingException er) {
			throw new ClientException(er);
		}

		HashMap<String, String> headers = new HashMap<String, String>();
		if (metadata != null) {
			OSSUtils.populateRequestMetadata(headers, metadata);
		} 
		headers.put("Content-Type", "text/plain");
		headers.put("Content-Length", Integer.toString(requestBytes.length));
		
		HashMap<String, String> queryParameters = new HashMap<String, String>();
		queryParameters.put("group", null);
		
		ResponseMessage msg = null;
		try{
			msg = this.request(HttpMethod.POST, bucket, key,
					headers, queryParameters, 
					new ByteArrayInputStream(requestBytes), requestBytes.length);
			return parseCreateObjectGroupResult(msg);	
		} catch(Exception er){
			System.out.println(er.getMessage());
			return null;
		} finally {
			closeResponseSilently(msg);
		}
	}

	private String buildObjectGroupRequestXml(List<Part> parts)
			throws IllegalArgumentException {
		StringBuffer xml = new StringBuffer();
		xml.append("<CreateFileGroup>");
		for (Part part : parts) {
			xml.append("<Part>");
			xml.append("<PartNumber>" + part.getIndex() + "</PartNumber>");
			xml.append("<PartName>" + part.getKey() + "</PartName>");
			xml.append("<ETag>" + part.getETag() + "</ETag>");
			xml.append("</Part>");
		}
		xml.append("</CreateFileGroup>");
		return xml.toString();
	}

	private CreateObjectGroupResult parseCreateObjectGroupResult(
			ResponseMessage msg) throws ClientException {
		Element root = getRootElement(msg.getContent());
		CreateObjectGroupResult result = new CreateObjectGroupResult();
		try {
			result.setBucket(root.getChildText("Bucket"));
			result.setKey(root.getChildText("Key"));
			result.setETag("ETag");
			result.setSize(Long.parseLong(root.getChildText("Size")));
		} catch (Exception er) {
			throw new ClientException("response parse error", er);
		}
		return result;
	}

	private Element getRootElement(InputStream content) throws ClientException {
		SAXBuilder builder = new SAXBuilder();
		try {
			Document document = builder.build(content);
			return document.getRootElement();
		} catch (Exception er) {
			throw new ClientException("respones builder error", er);
		}
	}
}
